package com.pervasa.demo.kitsample.impl;

import java.util.Vector;

import com.pervasa.demo.kitsample.impl.EventTree.NoChildrenException;
import com.pervasa.demo.kitsample.impl.EventTree.TRUTH;

public class PlanEvaluator {
	public PlanEvaluator(EventTree root)
	{
		this.root = root;
		tevents = EventTree.getTerminalEvents(root);
		bestPerformance = tevents.size();
	}
	
	double bestPerformance = 0;
	Vector<TerminalEvent> bestOrder = new Vector<TerminalEvent>();
	EventTree root = null;
	Vector<TerminalEvent> tevents = new Vector<TerminalEvent>();
	
	public Vector<TerminalEvent> getBestPlan()
	{
		return bestOrder;
	}

	public void evaluatePlan(Vector<TerminalEvent> orderedEvents) throws NoChildrenException {		
		for (TerminalEvent te : orderedEvents)
		{
			te.setTruth(TRUTH.UNKNOWN);
		}
		
		double expectedSensing = evaluatePlan(orderedEvents, 1.0, 0, 0);

		if (expectedSensing < bestPerformance)
		{
			bestPerformance = expectedSensing;
			bestOrder = (Vector<TerminalEvent>) orderedEvents.clone();
		}
	}
	
	public double evaluatePlan(Vector<TerminalEvent> orderedEvents, double probability, int index, int countOfPushEvent) throws NoChildrenException 
	{
		//if there are *seconds* tree, you may not find expected value for it.
		//I am not sure what is proper return value in this case.
		if (index >= orderedEvents.size())
		{
			return probability * (double)index;
		}
		
		
		
		double expectedSensing = 0.0;
		TerminalEvent te = orderedEvents.get(index);
		int countOfPushIncludingThis = countOfPushEvent;
		if (!te.isPullEvent())
			countOfPushIncludingThis += 1;
			
		te.setTruth(TRUTH.TRUE);
		double newProbability = probability * te.getProbability();
		
		if (root.evaluate() != TRUTH.UNKNOWN)
			expectedSensing += newProbability * (double)(index + 1 - countOfPushIncludingThis);
		else
			expectedSensing += evaluatePlan(orderedEvents, newProbability, index + 1, countOfPushIncludingThis);
		
		te.setTruth(TRUTH.FALSE);
		newProbability = probability * te.getProbability();
		if (root.evaluate() != TRUTH.UNKNOWN)
			expectedSensing += newProbability * (double)(index + 1 - countOfPushIncludingThis);
		else
			expectedSensing += evaluatePlan(orderedEvents, newProbability, index + 1, countOfPushIncludingThis);
		
		te.setTruth(TRUTH.UNKNOWN);
		return expectedSensing;
	}
	
	public void evaluateAllPlans() throws NoChildrenException
	{
		Vector<TerminalEvent> orderedEvents = new Vector<TerminalEvent>();
		nextCombination(tevents, orderedEvents);
	}
	
	private void nextCombination(Vector<TerminalEvent> tevents, Vector<TerminalEvent> orderedEvents) throws NoChildrenException
	{
		if (tevents.size() == orderedEvents.size())
		{
			evaluatePlan(orderedEvents);
			return;			
		}
		
		for (int i = 0; i < tevents.size(); i++)
		{
			if (orderedEvents.contains(tevents.get(i)))
				continue;
			orderedEvents.add(tevents.get(i));
			nextCombination(tevents, orderedEvents);
			orderedEvents.removeElementAt(orderedEvents.size() - 1);
		}
	}
}
